using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;

using NBear.Common;

namespace NBear.IoC.Service.Services
{
    public class DynamicService : BaseService
    {
        public static int DefaultExpireMinutes = 30;
        public static EntitySerializer DefaultEntitySerializer = new EntitySerializer(EntitySerializeType.Json);
        private IServiceContainer container;
        private Type serviceInterfaceType;

        public DynamicService(IServiceContainer container, Type serviceInterfaceType)
            : base(serviceInterfaceType.FullName, container.MQ)
        {
            this.container = container;
            this.OnLog += new LogHandler(container.WriteLog);
            this.serviceInterfaceType = serviceInterfaceType;
        }

        protected override ResponseMessage Run(RequestMessage msg)
        {
            if (container == null || msg == null)
            {
                return null;
            }

            IServiceInterface service = default(IServiceInterface);

            try
            {
                service = (IServiceInterface)container[serviceInterfaceType];
            }
            catch
            {
            }

            if (service == null)
            {
                return null;
            }

            MethodInfo mi = serviceInterfaceType.GetMethod(msg.SubServiceName);

            if (mi == null)
            {
                return null;
            }

            ParameterInfo[] pis = mi.GetParameters();
            object[] parms = new object[pis.Length];

            for (int i = 0; i < pis.Length; i++)
            {
                object val;
                Type type = pis[i].ParameterType;
                if (typeof(IEntity).IsAssignableFrom(type))
                {
                    val = typeof(EntitySerializer).GetMethod("Deserialize").MakeGenericMethod(type).Invoke(DefaultEntitySerializer, new object[] { msg.Parameters[pis[i].Name] });
                }
                else if (typeof(IEntity[]).IsAssignableFrom(type))
                {
                    val = typeof(EntitySerializer).GetMethod("DeserializeArray").MakeGenericMethod(type).Invoke(DefaultEntitySerializer, new object[] { msg.Parameters[pis[i].Name] });
                }
                else
                {
                    val = SerializeHelper.Deserialize(type, msg.Parameters[pis[i].Name]);
                }

                parms[i] = val;
            }

            ResponseMessage resMsg = new ResponseMessage();
            resMsg.Request = msg;
            resMsg.Expiration = DateTime.Now.AddMinutes(DefaultExpireMinutes);
            resMsg.MessageId = Guid.NewGuid();
            resMsg.ServiceName = serviceInterfaceType.FullName;
            resMsg.SubServiceName = mi.Name;
            resMsg.Timestamp = DateTime.Now;
            resMsg.TransactionId = msg.TransactionId;

            object returnValue = null;

            try
            {
                returnValue = mi.Invoke(service, parms);
            }
            catch
            {
                return null;
            }

            if (returnValue != null)
            {
                Type returnType = mi.ReturnType;

                if (returnType == typeof(System.Data.DataSet))
                {
                    resMsg.Data = (DataSet)returnValue;
                }
                else if (typeof(IEntity).IsAssignableFrom(returnType))
                {
                    resMsg.Text = DefaultEntitySerializer.Serialize(returnValue);
                }
                else if (typeof(IEntity[]).IsAssignableFrom(returnType))
                {
                    resMsg.Text = DefaultEntitySerializer.SerializeArray((Array)returnValue);
                }
                else
                {
                    resMsg.Text = SerializeHelper.Serialize(returnValue);
                }
            }

            return resMsg;
        }
    }
}
